home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / common / object.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  51KB  |  1,830 lines

  1. /*
  2.  * static char *rcsid_object_c =
  3.  *   "$Id: object.c,v 1.42 1996/07/24 07:03:36 master Exp master $";
  4.  */
  5.  
  6. /*
  7.     CrossFire, A Multiplayer game for X-windows
  8.  
  9.     Copyright (C) 1994 Mark Wedel
  10.     Copyright (C) 1992 Frank Tore Johansen
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26.     The author can be reached via e-mail to master@rahul.net
  27. */
  28.  
  29. /* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects.
  30.    sub/add_weight will transcend the environment updating the carrying
  31.    variable. */
  32.  
  33. #include <stdio.h>
  34. #include <sys/types.h>
  35. #include <sys/uio.h>
  36. #include <global.h>
  37. #include <object.h>
  38. #include <funcpoint.h>
  39. #include <skills.h> 
  40.  
  41. object objarray[STARTMAX]; /* All objects, allocated this way at first */
  42. object *objects;           /* Pointer to the list of used objects */
  43. object *free_objects;      /* Pointer to the list of unused objects */
  44. object *active_objects;    /* List of active objects that need to be processed */
  45.  
  46. int nroffreeobjects = STARTMAX;  /* How many OBs allocated and free (free) */
  47. int nrofallocobjects = STARTMAX; /* How many OBs allocated (free + used) */
  48.  
  49. int freearr_x[SIZEOFFREE]=
  50.   {0,0,1,1,1,0,-1,-1,-1,0,1,2,2,2,2,2,1,0,-1,-2,-2,-2,-2,-2,-1,
  51.    0,1,2,3,3,3,3,3,3,3,2,1,0,-1,-2,-3,-3,-3,-3,-3,-3,-3,-2,-1};
  52. int freearr_y[SIZEOFFREE]=
  53.   {0,-1,-1,0,1,1,1,0,-1,-2,-2,-2,-1,0,1,2,2,2,2,2,1,0,-1,-2,-2,
  54.    -3,-3,-3,-3,-2,-1,0,1,2,3,3,3,3,3,3,3,2,1,0,-1,-2,-3,-3,-3};
  55. int maxfree[SIZEOFFREE]=
  56.   {0,9,10,13,14,17,18,21,22,25,26,27,30,31,32,33,36,37,39,39,42,43,44,45,
  57.   48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49};
  58. int freedir[SIZEOFFREE]= {
  59.   0,1,2,3,4,5,6,7,8,1,2,2,2,3,4,4,4,5,6,6,6,7,8,8,8,
  60.   1,2,2,2,2,2,3,4,4,4,4,4,5,6,6,6,6,6,7,8,8,8,8,8};
  61.  
  62. /*
  63.  * sum_weight() is a recursive function which calculates the weight
  64.  * an object is carrying.  It goes through in figures out how much
  65.  * containers are carrying, and sums it up.
  66.  */
  67. signed long sum_weight(object *op) {
  68.   signed long sum;
  69.   object *inv;
  70.   for(sum = 0, inv = op->inv; inv != NULL; inv = inv->below) {
  71.     if (inv->inv)
  72.     sum_weight(inv);
  73.     sum += inv->carrying + (inv->nrof ? inv->weight * inv->nrof : inv->weight);
  74.   }
  75.   if (op->type == CONTAINER && op->stats.Str)
  76.     sum = (sum * (100 - op->stats.Str))/100;
  77.   if(op->carrying != sum)
  78.     op->carrying = sum;
  79.   return sum;
  80. }
  81.  
  82.  
  83. /*
  84.  * Eneq(@csd.uu.se): Since we can have items buried in a character we need
  85.  * a better check
  86.  */
  87.  
  88. object *is_player_inv (object *op) { 
  89.     for (;op!=NULL&&op->type!=PLAYER; op=op->env)
  90.       if (op->env==op)
  91.       op->env = NULL;
  92.     return op;
  93. }
  94.  
  95. /*
  96.  * Used by: Crossedit: dump. Server DM commands: dumpbelow, dump.
  97.  *    Some error messages.
  98.  * The result of the dump is stored in the static global errmsg array.
  99.  */
  100.  
  101. void dump_object2(object *op) {
  102.   char *cp;
  103. /*  object *tmp;*/
  104.  
  105.   if(op->arch!=NULL) {
  106.       strcat(errmsg,"arch ");
  107.       strcat(errmsg,op->arch->name?op->arch->name:"(null)");
  108.       strcat(errmsg,"\n");
  109.       if((cp=get_ob_diff(op,&empty_archetype->clone))!=NULL)
  110.     strcat(errmsg,cp);
  111. #if 0
  112.       /* Don't dump player diffs - they are too long, mostly meaningless, and
  113.        * will overflow the buffer.
  114.        * Changed so that we don't dump inventory either.  This may
  115.        * also overflow the buffer.
  116.        */
  117.       if(op->type!=PLAYER && (cp=get_ob_diff(op,&empty_archetype->clone))!=NULL)
  118.         strcat(errmsg,cp);
  119.       for (tmp=op->inv; tmp; tmp=tmp->below)
  120.         dump_object2(tmp);
  121. #endif
  122.       strcat(errmsg,"end\n");
  123.   } else {
  124.       strcat(errmsg,"Object ");
  125.       if (op->name==NULL) strcat(errmsg, "(null)");
  126.       else strcat(errmsg,op->name);
  127.       strcat(errmsg,"\n");
  128. #if 0
  129.       if((cp=get_ob_diff(op,&empty_archetype->clone))!=NULL)
  130.         strcat(errmsg,cp);
  131.       for (tmp=op->inv; tmp; tmp=tmp->below)
  132.         dump_object2(tmp);
  133. #endif
  134.       strcat(errmsg,"end\n");
  135.   }
  136. }
  137.  
  138. /*
  139.  * Dumps an object.  Returns output in the static global errmsg array.
  140.  */
  141.  
  142. void dump_object(object *op) {
  143.   if(op==NULL) {
  144.     strcpy(errmsg,"[NULL pointer]");
  145.     return;
  146.   }
  147.   errmsg[0]='\0';
  148.   dump_object2(op);
  149. }
  150.  
  151. /*
  152.  * This is really verbose...Can be triggered by the P key while in DM mode.
  153.  * All objects are dumped to stderr (or alternate logfile, if in server-mode)
  154.  */
  155.  
  156. void dump_all_objects() {
  157.   object *op;
  158.   for(op=objects;op!=NULL;op=op->next) {
  159.     dump_object(op);
  160.     fprintf(logfile, "Object %d\n:%s\n", op->count, errmsg);
  161.   }
  162. }
  163.  
  164. /*
  165.  * animate_object(object) updates the face-variable of an object.
  166.  * If the object is the head of a multi-object, all objects are animated.
  167.  * If the object has the IS_TURNING() flag, that is taken into consideration.
  168.  */
  169.  
  170. void animate_object(object *op) {
  171.   if(op->arch==NULL) {
  172.     dump_object(op);
  173.     LOG(llevError,"Tried to animate object without archetype:\n%s\n", errmsg);
  174.     return;
  175.   }
  176.   if(!op->arch->animations) {
  177.     LOG(llevError,"Archtype lacks animation.\n");
  178.     dump_arch(op->arch);
  179.   }
  180.   if((unsigned char) ++op->state >=
  181.      (int) (QUERY_FLAG(op,FLAG_IS_TURNING) ? op->arch->animations/2 : op->arch->animations))
  182.     op->state=0;
  183.   op->face=&new_faces[
  184.     op->arch->faces[op->state+(QUERY_FLAG(op,FLAG_IS_TURNING)?
  185.            ((op->head!=NULL?op->head:op)->value?op->arch->animations/2:0):0)]];
  186.   if(op->face==blank_face)
  187.     op->invisible=1;
  188. #if 1
  189.   else if(QUERY_FLAG((&op->arch->clone),FLAG_ALIVE)) {
  190.     if(op->face->number==0) {
  191.       op->invisible=1;
  192.       CLEAR_FLAG(op, FLAG_ALIVE);
  193.     } else {
  194.       op->invisible=0;
  195.       SET_FLAG(op, FLAG_ALIVE);
  196.     }
  197.   }
  198. #endif
  199.   update_object(op);
  200.   if(op->more)
  201.     animate_object(op->more);
  202. }
  203.  
  204. /*
  205.  * get_nearest_part(multi-object, object 2) returns the part of the
  206.  * multi-object 1 which is closest to the second object.
  207.  * If it's not a multi-object, it is returned.
  208.  */
  209.  
  210. object *get_nearest_part(object *op,object *pl) {
  211.   object *tmp,*closest;
  212.   int last_dist,i;
  213.   if(op->more==NULL)
  214.     return op;
  215.   for(last_dist=distance(op,pl),closest=op,tmp=op->more;tmp!=NULL;tmp=tmp->more)
  216.     if((i=distance(tmp,pl))<last_dist)
  217.       closest=tmp,last_dist=i;
  218.   return closest;
  219. }
  220.  
  221. /*
  222.  * Returns the object which has the count-variable equal to the argument.
  223.  */
  224.  
  225. object *find_object(int i) {
  226.   object *op;
  227.   for(op=objects;op!=NULL;op=op->next)
  228.     if(op->count==i)
  229.       break;
  230.  return op;
  231. }
  232.  
  233. /*
  234.  * Returns the first object which has a name equal to the argument.
  235.  * Used only by the patch command, but not all that useful.
  236.  * Enables features like "patch <name-of-other-player> food 999"
  237.  */
  238.  
  239. object *find_object_name(char *str) {
  240.   char *name=add_string(str);
  241.   object *op;
  242.   for(op=objects;op!=NULL;op=op->next)
  243.     if(op->name==name)
  244.       break;
  245.   free_string(name);
  246.   return op;
  247. }
  248.  
  249. /*
  250.  * Returns the object which this object marks as being the owner.
  251.  * A id-scheme is used to avoid pointing to objects which have been
  252.  * freed and are now reused.  If this is detected, the owner is
  253.  * set to NULL, and NULL is returned.
  254.  * (This scheme should be changed to a refcount scheme in the future)
  255.  */
  256.  
  257. object *get_owner(object *op) {
  258.   if(op->owner==NULL)
  259.     return NULL;
  260.   if(!QUERY_FLAG(op->owner,FLAG_FREED) && op->owner->count==op->ownercount)
  261.     return op->owner;
  262.   op->owner=NULL,op->ownercount=0;
  263.   return NULL;
  264. }
  265.  
  266. /*
  267.  * Sets the owner of the first object to the second object.
  268.  * Also checkpoints a backup id-scheme which detects freeing (and reusage)
  269.  * of the owner object.
  270.  * See also get_owner()
  271.  */
  272.  
  273. void set_owner(object *op, object *owner) {
  274.   if(owner==NULL||op==NULL)
  275.     return;
  276.   /* next line added to allow objects which own objects */ 
  277.   while(owner->owner&&owner!=owner->owner) owner=owner->owner;
  278.     op->owner=owner;
  279.  
  280.   op->ownercount=owner->count;
  281.   owner->refcount++;
  282.  
  283. #ifdef ALLOW_SKILLS /* set the pointers in op to inherit owners skill, exp_obj */ 
  284.   if(owner->type==PLAYER&&owner->chosen_skill) {
  285.         op->chosen_skill = owner->chosen_skill;
  286.         op->exp_obj = owner->chosen_skill->exp_obj;
  287.  
  288.     /* unfortunately, we can't allow summoned monsters skill use
  289.          * because we will need the chosen_skill field to pick the
  290.          * right skill/stat modifiers for calc_skill_exp(). See
  291.          * hit_player() in server/attack.c -b.t. */
  292.   } else if(op->type!=PLAYER && QUERY_FLAG(op,FLAG_READY_SKILL))
  293.                CLEAR_FLAG(op,FLAG_READY_SKILL);
  294. #endif
  295. }
  296.  
  297. /*
  298.  * Resets vital variables in an object
  299.  */
  300.  
  301. void reset_object(object *op) {
  302.   op->name = NULL;
  303.   op->title = NULL;
  304.   op->race = NULL;
  305.   op->slaying = NULL;
  306.   op->msg = NULL;
  307.   clear_object(op);
  308. }
  309. /*
  310.  * clear_object() frees everything allocated by an object, and also
  311.  * clears all variables and flags to default settings.
  312.  */
  313.  
  314. void clear_object(object *op) {
  315.    int tmp;
  316.  
  317.   if(op->name!=NULL) {
  318.     free_string(op->name);
  319.     op->name=NULL;
  320.   }
  321.   if(op->title != NULL) {
  322.     free_string(op->title);
  323.     op->title = NULL;
  324.   }
  325.   if(op->race!=NULL) {
  326.     free_string(op->race);
  327.     op->race=NULL;
  328.   }
  329.   if(op->slaying!=NULL) {
  330.     free_string(op->slaying);
  331.     op->slaying=NULL;
  332.   }
  333.   if(op->msg!=NULL) {
  334.     free_string(op->msg);
  335.     op->msg=NULL;
  336.   }
  337.   for (tmp=0; tmp<=(NUM_FLAGS/32); tmp++)
  338.     op->flags[tmp] = 0;
  339.   op->map=NULL;
  340.   op->below=NULL;
  341.   op->above=NULL;
  342.   op->owner=NULL;
  343.   op->refcount=0;
  344.   op->inv=NULL;
  345.   op->env=NULL;
  346.   op->container=NULL;
  347.   op->more=NULL;
  348.   op->head=NULL;
  349.   op->arch=NULL;
  350.   op->other_arch=NULL;
  351.   op->enemy=NULL;
  352.   op->weight=0,op->carrying=0,op->weight_limit=0;
  353.   op->anim_speed=0;
  354.   op->level=0;
  355.   op->value=op->run_away=0;
  356.   op->invisible=0;
  357.   op->last_heal=0,op->last_sp=0,op->last_eat=0;
  358.   op->nrof=0;
  359.   op->ownercount=0;
  360.   op->immune=0,op->protected=0,op->attacktype=0,op->vulnerable=0;
  361.   op->stats.exp=0;
  362.   op->x=0; op->y=0; op->ox=0; op->oy=0;
  363.   op->stats.dam=0,op->stats.wc=0,op->stats.ac=0;
  364.   op->armour=0;
  365.   op->stats.luck=0;
  366.   op->stats.food=0;
  367.   op->stats.sp=op->stats.maxsp=op->stats.hp=op->stats.maxhp=0;
  368.   op->stats.grace=op->stats.maxgrace=0;
  369.   op->expmul=1.0;
  370.   op->direction=0;
  371.   op->glow_radius=0;
  372. #ifdef NPC_PROG
  373.   op->npc_status=0;
  374.   op->npc_program=0;
  375. #endif
  376.   op->stats.Str=op->stats.Dex=op->stats.Con=0;
  377.   op->stats.Wis=op->stats.Cha=op->stats.Int=op->stats.Pow=0;
  378.   op->material=op->magic=op->state=op->type=0;
  379.   op->face = blank_face;
  380.  
  381.   /* The object should already have been removed from the speed list
  382.    * before this function is called
  383.    */
  384.   op->speed=op->speed_left=0;
  385.   op->pick_up=0;
  386.   op->can_apply=0;
  387.   op->will_apply=0;
  388.   op->move_status = 0;
  389.   op->move_type = 0;
  390.   op->path_repelled = 0;
  391.   op->path_attuned = 0;
  392.   op->path_denied = 0;
  393. #ifdef CASTING_TIME
  394.   op->casting = -1;
  395.   op->spell = NULL;
  396.   op->spelltype = 0;
  397. #endif
  398.  
  399. }
  400.  
  401. /*
  402.  * copy object first frees everything allocated by the second object,
  403.  * and then copies the contends of the first object into the second
  404.  * object, allocating what needs to be allocated.
  405.  */
  406.  
  407. void copy_object(object *op2, object *op) {
  408.   int is_freed=QUERY_FLAG(op,FLAG_FREED),is_removed=QUERY_FLAG(op,FLAG_REMOVED);
  409.  
  410.   if(op->name!=NULL)
  411.     free_string(op->name);
  412.   if(op->title!=NULL)
  413.     free_string(op->title);
  414.   if(op->race!=NULL)
  415.     free_string(op->race);
  416.   if(op->slaying!=NULL)
  417.     free_string(op->slaying);
  418.   if(op->msg!=NULL)
  419.     free_string(op->msg);
  420.   (void) memcpy((void *)((char *) op +offsetof(object,name)),
  421.                 (void *)((char *) op2+offsetof(object,name)),
  422.                 sizeof(object)-offsetof(object, name));
  423.   if(is_freed)
  424.     SET_FLAG(op,FLAG_FREED);
  425.   if(is_removed)
  426.     SET_FLAG(op,FLAG_REMOVED);
  427.   if(op->name!=NULL)
  428.     add_refcount(op->name);
  429.   if(op->title!=NULL)
  430.     add_refcount(op->title);
  431.   if(op->race!=NULL)
  432.     add_refcount(op->race);
  433.   if(op->slaying!=NULL)
  434.     add_refcount(op->slaying);
  435.   if(op->msg!=NULL)
  436.     add_refcount(op->msg);
  437.   if(op2->speed<0)
  438.     op->speed_left=op2->speed_left-RANDOM()%200/100.0;
  439.   update_ob_speed(op);
  440. }
  441.  
  442. /*
  443.  * expand_objects() allocates more objects for the list of unused objects.
  444.  * It is called from get_object() if the unused list is empty.
  445.  */
  446.  
  447. void expand_objects() {
  448.   int i;
  449.   object *new;
  450.   new = (object *) CALLOC(OBJ_EXPAND,sizeof(object));
  451.  
  452.   if(new==NULL)
  453.     fatal(OUT_OF_MEMORY);
  454.   free_objects=new;
  455.   new[0].prev=NULL;
  456.   new[0].next= &new[1],
  457.   SET_FLAG(&(new[0]), FLAG_REMOVED);
  458.   SET_FLAG(&(new[0]), FLAG_FREED);
  459.  
  460.   for(i=1;i<OBJ_EXPAND-1;i++) {
  461.     new[i].next= &new[i+1],
  462.     new[i].prev= &new[i-1],
  463.     SET_FLAG(&(new[i]), FLAG_REMOVED);
  464.     SET_FLAG(&(new[i]), FLAG_FREED);
  465.   }
  466.   new[OBJ_EXPAND-1].prev= &new[OBJ_EXPAND-2],
  467.   new[OBJ_EXPAND-1].next=NULL,
  468.   SET_FLAG(&(new[OBJ_EXPAND-1]), FLAG_REMOVED);
  469.   SET_FLAG(&(new[OBJ_EXPAND-1]), FLAG_FREED);
  470.  
  471.   nrofallocobjects += OBJ_EXPAND;
  472.   nroffreeobjects += OBJ_EXPAND;
  473. }
  474.  
  475. /*
  476.  * get_object() grabs an object from the list of unused objects, makes
  477.  * sure it is initialised, and returns it.
  478.  * If there are no free objects, expand_objects() is called to get more.
  479.  */
  480.  
  481. object *get_object() {
  482.   object *op;
  483.   if(free_objects==NULL) {
  484.     expand_objects();
  485.   }
  486.   op=free_objects;
  487.   if(!QUERY_FLAG(op,FLAG_FREED)) {
  488.     LOG(llevError,"Fatal: Getting busy object.\n");
  489.   }
  490.   free_objects=op->next;
  491.   if(free_objects!=NULL)
  492.     free_objects->prev=NULL;
  493.   op->count= ++ob_count;
  494.   op->name=NULL;
  495.   op->title=NULL;
  496.   op->race=NULL;
  497.   op->slaying=NULL;
  498.   op->msg=NULL;
  499.   op->next=objects;
  500.   op->prev=NULL;
  501.   op->active_next = NULL;
  502.   op->active_prev = NULL;
  503.   if(objects!=NULL)
  504.     objects->prev=op;
  505.   objects=op;
  506.   clear_object(op);
  507.   SET_FLAG(op,FLAG_REMOVED);
  508.   nroffreeobjects--;
  509.   return op;
  510. }
  511.  
  512. /*
  513.  * If an object with the IS_TURNABLE() flag needs to be turned due
  514.  * to the closest player being on the other side, this function can
  515.  * be called to update the face variable, _and_ how it looks on the map.
  516.  */
  517.  
  518. void update_turn_face(object *op) {
  519.   if(!QUERY_FLAG(op,FLAG_IS_TURNABLE)||op->arch==NULL)
  520.     return;
  521.   op->face=&new_faces[op->arch->faces[op->direction]];
  522.   update_object(op);
  523. }
  524.  
  525. /*
  526.  * Updates the speed of an object.  If the speed changes from 0 to another
  527.  * value, or vice versa, then add/remove the object from the active list.
  528.  * This function needs to be called whenever the speed of an object changes.
  529.  */
  530.  
  531. void update_ob_speed(object *op) {
  532.     extern int arch_init;
  533.  
  534.     /* No reason putting the archetypes objects on the speed list,
  535.      * since they never really need to be updated.
  536.      */
  537.  
  538.     if (QUERY_FLAG(op, FLAG_FREED) && op->speed) {
  539.     LOG(llevError,"Object %s is freed but has speed.\n", op->name);
  540. #ifdef MANY_CORES
  541.     abort();
  542. #endif
  543.     op->speed = 0;
  544.     }
  545.     if (arch_init) {
  546.     return;
  547.     }
  548.     if (op->speed) {
  549.     /* If already on active list, don't do anything */
  550.     if (op->active_next || op->active_prev || op==active_objects)
  551.         return;
  552.  
  553.     op->active_next = active_objects;
  554.     if (op->active_next!=NULL)
  555.         op->active_next->active_prev = op;
  556.     active_objects = op;
  557.     }
  558.     else {
  559.     /* If not on the active list, nothing needs to be done */
  560.     if (!op->active_next && !op->active_prev && op!=active_objects)
  561.         return;
  562.  
  563.     if (op->active_prev==NULL) {
  564.         active_objects = op->active_next;
  565.         if (op->active_next!=NULL)
  566.         op->active_next->active_prev = NULL;
  567.     }
  568.     else {
  569.         op->active_prev->active_next = op->active_next;
  570.         if (op->active_next)
  571.         op->active_next->active_prev = op->active_prev;
  572.     }
  573.     op->active_next = NULL;
  574.     op->active_prev = NULL;
  575.     }
  576. }
  577.  
  578.  
  579. /*
  580.  * update_object() updates the array which represents the map.
  581.  * It takes into account invisible objects (and represent squares covered
  582.  * by invisible objects by whatever is below them (unless it's another
  583.  * invisible object, etc...))
  584.  * If the object being updated is beneath a player, the look-window
  585.  * of that player is updated (this might be a suboptimal way of
  586.  * updating that window, though, since update_object() is called _often_)
  587.  */
  588.  
  589. void update_object(object *op) {
  590.   object *tmp;
  591.  
  592.   if(op->env!=NULL) {
  593.     if((tmp=is_player_inv(op->env)))
  594.       (*draw_inventory_faces_func)(tmp);
  595.     return;
  596.   }
  597.  
  598.  /* Can be null if the player has quit but window still exists. */
  599.   if (op->map->map != NULL)
  600.       update_position (op->map, op->x, op->y);
  601.  
  602.   if(op->more!=NULL)
  603.     update_object(op->more);
  604. }
  605.  
  606.  
  607. /* This updates how the map looks at a specified space.  We use
  608.  * some time saving techniques instead of space - each map has 2 or
  609.  * 3 arrays - one for floors, one for top object, and one for an
  610.  * additional object (if DOUBLE_FLOOR patch).  Changed things around
  611.  * so that we now have a visibility flag, and if that is set, then the
  612.  * highest object with that visibility gets put into the addition object
  613.  * slot.
  614.  */
  615. void update_position (mapstruct *m, int x, int y) {
  616.     object *tmp, *last = NULL;
  617.     unsigned int flags = 0;
  618.     MapLook f=blank_look;
  619. #ifdef DOUBLE_FLOOR
  620.     MapLook f1 = blank_look;
  621. #endif
  622.  
  623.     for (tmp = get_map_ob (m, x, y); tmp; last = tmp, tmp = tmp->above) {
  624.  
  625.     /* This call is needed in order to update objects the player
  626.      * is standign in that have animations (ie, grass, fire, etc).
  627.      * However, it also causes the look window to be re-drawn
  628.      * 3 times each time the player moves, because many of the
  629.      * functions the move_player calls eventualy call this.
  630.      *
  631.      * Always put the player down for drawing.
  632.      */
  633.     if (tmp->type==PLAYER) {
  634.         (*draw_look_faces_func)(tmp);
  635.         f.face = tmp->face;
  636.     }
  637. #ifdef DOUBLE_FLOOR
  638.     else if (f1.face->visibility < tmp->face->visibility && !tmp->invisible)
  639.         f1.face = tmp->face;
  640. #endif
  641.     if (tmp==tmp->above) {
  642.         LOG(llevError, "Error in structure of map\n");
  643.         exit (-1);
  644.     }
  645.       
  646.     if (QUERY_FLAG(tmp,FLAG_ALIVE))
  647.         flags |= P_IS_ALIVE;
  648.     if (QUERY_FLAG(tmp,FLAG_NO_PASS))
  649.         flags |= P_NO_PASS;
  650.     if (QUERY_FLAG(tmp,FLAG_NO_MAGIC))
  651.         flags |= P_NO_MAGIC;
  652.     if (QUERY_FLAG(tmp,FLAG_DAMNED))
  653.         flags |= P_NO_CLERIC;
  654.     if (QUERY_FLAG(tmp,FLAG_PASS_THRU))
  655.         flags |= P_PASS_THRU;
  656.     if (QUERY_FLAG(tmp,FLAG_BLOCKSVIEW))
  657.         flags |= P_BLOCKSVIEW;
  658.     }
  659.     if (last && f.face==blank_face) f.face = last->face;
  660.  
  661.     /* If using the editor, show invisible faces */
  662.     if (!editor) {
  663.     while (last && (last->invisible || !last->face->number))
  664.         last = last->below;
  665.  
  666.     if (last!=NULL) f.face = last->face;
  667.     else f.face = blank_face;
  668.     }
  669. #ifdef DOUBLE_FLOOR
  670.     if (f.face == f1.face)
  671.     f1.face = blank_face;
  672.     set_map_floor2(m, x, y, &f1);
  673. #endif
  674.  
  675.     f.flags = flags;
  676.     set_map (m, x, y, &f);
  677.  
  678.     return;
  679. }
  680.  
  681. /*
  682.  * free_object() frees everything allocated by an object, removes
  683.  * it from the list of used objects, and puts it on the list of
  684.  * free objects.  The IS_FREED() flag is set in the object.
  685.  * The object must have been removed by remove_ob() first for
  686.  * this function to succeed.
  687.  */
  688.  
  689. void free_object(object *ob) {
  690.   object *tmp,*op;
  691.   if(QUERY_FLAG(ob,FLAG_FRIENDLY)) {
  692.     LOG(llevMonster,"Warning: tried to free friendly object.\n");
  693.     (*remove_friendly_object_func)(ob);
  694.   }
  695.   if(QUERY_FLAG(ob,FLAG_FREED)) {
  696.     dump_object(ob);
  697.     LOG(llevError,"Trying to free freed object.\n%s\n",errmsg);
  698.     return;
  699.   }
  700.   if(ob->more!=NULL) {
  701.     free_object(ob->more);
  702.     ob->more=NULL;
  703.   }
  704.   if (ob->inv) {
  705.     if (ob->map==NULL || ob->map->in_memory!=MAP_IN_MEMORY ||
  706.        wall(ob->map,ob->x,ob->y))
  707.     {
  708.       op=ob->inv;
  709.       while(op!=NULL) {
  710.         tmp=op->below;
  711.         remove_ob(op);
  712.         free_object(op);
  713.         op=tmp;
  714.       }
  715.     }
  716.     else {
  717.       op=ob->inv;
  718.       while(op!=NULL) {
  719.         tmp=op->below;
  720.         remove_ob(op);
  721.         if(QUERY_FLAG(op,FLAG_STARTEQUIP)||QUERY_FLAG(op,FLAG_NO_DROP) ||
  722.       op->type==RUNE)
  723.           free_object(op);
  724.         else {
  725.           op->x=ob->x,op->y=ob->y;
  726.           insert_ob_in_map(op,ob->map); /* Insert in same map as the envir */
  727.         }
  728.         op=tmp;
  729.       }
  730.     }
  731.   }
  732.   /* Remove object from the active list */
  733.   ob->speed = 0;
  734.   update_ob_speed(ob);
  735.  
  736.   SET_FLAG(ob, FLAG_FREED);
  737.   /* First free the object from the used objects list: */
  738.   if(ob->prev==NULL) {
  739.     objects=ob->next;
  740.     if(objects!=NULL)
  741.       objects->prev=NULL;
  742.   }
  743.   else {
  744.     ob->prev->next=ob->next;
  745.     if(ob->next!=NULL)
  746.       ob->next->prev=ob->prev;
  747.   }
  748.   
  749.   /* Now link it with the free_objects list: */
  750.   ob->prev=NULL;
  751.   ob->next=free_objects;
  752.   if(free_objects!=NULL)
  753.     free_objects->prev=ob;
  754.   free_objects=ob;
  755.   if(ob->name!=NULL) {
  756.     free_string(ob->name);
  757.     ob->name=NULL;
  758.   }
  759.   if(ob->title!=NULL) {
  760.     free_string(ob->title);
  761.     ob->title=NULL;
  762.   }
  763.   if(ob->race!=NULL) {
  764.     free_string(ob->race);
  765.     ob->race=NULL;
  766.   }
  767.   if(ob->slaying!=NULL) {
  768.     free_string(ob->slaying);
  769.     ob->slaying=NULL;
  770.   }
  771.   if(ob->msg!=NULL) {
  772.     free_string(ob->msg);
  773.     ob->msg=NULL;
  774.   }
  775.   nroffreeobjects++;
  776. }
  777.  
  778. /*
  779.  * count_free() returns the number of objects on the list of free objects.
  780.  */
  781.  
  782. int count_free() {
  783.   int i=0;
  784.   object *tmp=free_objects;
  785.   while(tmp!=NULL)
  786.     tmp=tmp->next, i++;
  787.   return i;
  788. }
  789.  
  790. /*
  791.  * count_used() returns the number of objects on the list of used objects.
  792.  */
  793.  
  794. int count_used() {
  795.   int i=0;
  796.   object *tmp=objects;
  797.   while(tmp!=NULL)
  798.     tmp=tmp->next, i++;
  799.   return i;
  800. }
  801.  
  802. /*
  803.  * count_active() returns the number of objects on the list of active objects.
  804.  */
  805.  
  806. int count_active() {
  807.   int i=0;
  808.   object *tmp=active_objects;
  809.   while(tmp!=NULL)
  810.     tmp=tmp->active_next, i++;
  811.   return i;
  812. }
  813.  
  814. /*
  815.  * sub_weight() recursively (outwards) subtracts a number from the
  816.  * weight of an object (and what is carried by it's environment(s)).
  817.  */
  818.  
  819. void sub_weight (object *op, signed long weight) {
  820.   while (op != NULL) {
  821.     if (op->type == CONTAINER) {
  822.       weight=(signed long)(weight*(100-op->stats.Str)/100);
  823.     }
  824.     op->carrying-=weight;
  825.     op = op->env;
  826.   }
  827. }
  828.  
  829. /* remove_ob(op):
  830.  *   This function removes the object op from the linked list of objects
  831.  *   which it is currently tied to.  When this function is done, the
  832.  *   object will have no environment.  If the object previously had an
  833.  *   environment, the x and y coordinates will be updated to
  834.  *   the previous environment.
  835.  *   Beware: This function is called from the editor as well!
  836.  */
  837.  
  838. void remove_ob(object *op) {
  839.   object *tmp,*last=NULL;
  840.   object *otmp;
  841.  
  842.   if(QUERY_FLAG(op,FLAG_REMOVED)) {
  843.     dump_object(op);
  844.     LOG(llevError,"Trying to remove removed object.\n%s\n",errmsg);
  845.  
  846. /* Might as well dump core here.  In most cases, the function calling
  847.  * remove_ob makes assumptions about success, and the validity of the
  848.  * next, above, and below pointers, and a core dump would probably result
  849.  * shortly anyways.
  850.  */
  851. #ifdef MANY_CORES
  852.     abort();
  853. #else
  854.     if(op->map!=NULL && op->map->in_memory == MAP_IN_MEMORY) {
  855.       op->map->need_refresh=1;
  856.       LOG(llevDebug,"Marked map %s for refresh.\n",op->map->path);
  857.     }
  858. #endif
  859.     if(get_map_ob(op->map,op->x,op->y)==op)
  860.     { /* we are at bottom [Smart! -Frank] */
  861.        if (op->below)
  862.       set_map_ob(op->map,op->x,op->y,op->below);
  863.        else if (op->above)
  864.       set_map_ob(op->map,op->x,op->y,op->above);
  865.        else 
  866.       set_map_ob(op->map,op->x,op->y,NULL);
  867.     }
  868.     return; /* Why did you comment this away at DoCS?? It just makes it worse */
  869.   }
  870.   if(op->more!=NULL)
  871.     remove_ob(op->more);
  872.   SET_FLAG(op, FLAG_REMOVED);
  873.   if(op->env!=NULL) {
  874.     if(op->nrof)
  875.       sub_weight(op->env, op->weight*op->nrof);
  876.     else
  877.       sub_weight(op->env, op->weight+op->carrying);
  878.     if ((otmp=is_player_inv(op->env))!=NULL)
  879.       fix_player(otmp);
  880.     if(op->above!=NULL)
  881.       op->above->below=op->below;
  882.     else
  883.       op->env->inv=op->below;
  884.     if(op->below!=NULL)
  885.       op->below->above=op->above;
  886.     op->x=op->env->x,op->y=op->env->y;
  887.     op->ox=op->x,op->oy=op->y;
  888.     op->map=op->env->map;
  889.     op->above=NULL,op->below=NULL;
  890.     if(otmp!=NULL) {
  891.       if (otmp->type==PLAYER && !otmp->contr->eric_server)
  892.     (*draw_inventory_func)(otmp);
  893.     }
  894.     op->env=NULL;
  895.     return;
  896.   }
  897.   if (op->map == NULL) return;
  898.   if(out_of_map(op->map,op->x,op->y))
  899.     op->x=0,op->y=0,op->ox=0,op->oy=0;
  900.   if(op->above!=NULL) {                /* Don't change map, we're not on top */
  901.     op->above->below=op->below;        /* Link above with below */
  902.     if(op->below!=NULL) {              /* Something below us? */
  903.       op->below->above=op->above;      /* Yes, link above with below */
  904.       op->below=NULL;
  905.     }
  906.     else {                             /* Nothing below, tell the floor what */
  907.       if(get_map_ob(op->map,op->x,op->y)!=op) {
  908.         dump_object(op);
  909.         LOG(llevError,"Object squizez another object:\n%s\n",errmsg);
  910.         dump_object(get_map_ob(op->map,op->x,op->y));
  911.         LOG(llevError,"%s\n",errmsg);
  912.       }
  913.       set_map_ob(op->map,op->x,op->y,op->above);  /* goes on above it. */
  914.     }
  915.     op->above=NULL;                      
  916.   }
  917.   else if(op->below!=NULL) {
  918.     op->below->above=NULL,             /* It is now on top */
  919.     op->below=NULL;
  920.   } else {
  921.       if(get_map_ob(op->map,op->x,op->y)!=op) {
  922.         LOG(llevError,"Object squizez another object:\n");
  923.         dump_object(op);
  924.         LOG(llevError,"%s\n",errmsg);
  925.         dump_object(get_map_ob(op->map,op->x,op->y));
  926.         LOG(llevError,"%s\n",errmsg);
  927.       }
  928.     set_map_ob(op->map,op->x,op->y,NULL);           /* No more objects here */
  929.   }
  930.   for(tmp=get_map_ob(op->map,op->x,op->y);tmp!=NULL;tmp=tmp->above) {
  931.     /* No point updating the players look faces if he is the object
  932.      * being removed.
  933.      */
  934.     if(tmp->type==PLAYER && tmp!=op)
  935.       (*draw_look_func)(tmp);
  936.     if(QUERY_FLAG(op,FLAG_FLYING)?QUERY_FLAG(tmp,FLAG_FLY_OFF):
  937.       QUERY_FLAG(tmp,FLAG_WALK_OFF))
  938.         (*apply_func)(op,tmp);
  939.  
  940.     /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */
  941.  
  942.     if(tmp->above == tmp)
  943.       tmp->above = NULL;
  944.     last=tmp;
  945.   }  
  946.   if(last==NULL)    /* No more objects present, draw the background */
  947.     set_map(op->map,op->x,op->y,&blank_look);
  948.   else            /* Redraw the object at the top */
  949.     update_object(last);
  950.  
  951.   if(QUERY_FLAG(op,FLAG_BLOCKSVIEW)    /* Should be harmless from editor, */
  952. #ifdef USE_LIGHTING
  953.      ||(op->glow_radius>0) 
  954. #endif
  955.   ) 
  956.     update_all_los(op->map);    /* first_player is no longer set there */
  957.  
  958. }
  959.  
  960. /*
  961.  * merge_ob(op,top):
  962.  *
  963.  * This function goes through all objects below and including top, and
  964.  * merges op to the first matching object.
  965.  * If top is NULL, it is calculated.
  966.  * Returns pointer to object if it succeded in the merge, otherwise NULL
  967.  */
  968.  
  969. object *merge_ob(object *op, object *top) {
  970.   if(!op->nrof)
  971.     return 0;
  972.   if(top==NULL)
  973.     for(top=op;top!=NULL&&top->above!=NULL;top=top->above);
  974.   for(;top!=NULL;top=top->below) {
  975.     if(top==op)
  976.       continue;
  977.     if (CAN_MERGE(op,top))
  978.     {
  979.       top->nrof+=op->nrof;
  980.       CLEAR_FLAG(top,FLAG_STARTEQUIP);
  981.       op->weight = 0; /* Don't want any adjustements now */
  982.       remove_ob(op);
  983.       free_object(op);
  984.       return top;
  985.     }
  986.   }
  987.   return NULL;
  988. }
  989.  
  990.  
  991. /* This is a simple version of the insert_ob_in_map function below. 
  992.  * We do stuff similar to insert_ob_in_map, but don't merge objects
  993.  * or check apply.  This is needed by at least the polymorph function -
  994.  * it expects the next object below it to still be around, and if the
  995.  * object gets merged, it gets removed
  996.  */
  997.  
  998. void insert_ob_in_map_simple(object *op, mapstruct *m)
  999. {
  1000.   object *tmp, *top;
  1001.  
  1002.   if(m==NULL) {
  1003.     dump_object(op);
  1004.     LOG(llevError,"Trying to insert in null-map!\n%s\n",errmsg);
  1005.     return;
  1006.   }
  1007.   if(out_of_map(m,op->x,op->y)) {
  1008.     dump_object(op);
  1009.     LOG(llevError,"Trying to insert object outside the map.\n%s\n", errmsg);
  1010.     return;
  1011.   }
  1012.   if(!QUERY_FLAG(op,FLAG_REMOVED)) {
  1013.     dump_object(op);
  1014.     LOG(llevError,"Trying to insert (map) inserted object.\n%s\n", errmsg);
  1015.     return;
  1016.   }
  1017.   if(op->more!=NULL)
  1018.     insert_ob_in_map_simple(op->more,m);
  1019.   CLEAR_FLAG(op,FLAG_REMOVED);
  1020.   op->ox=op->x,op->oy=op->y;
  1021.   op->map=m;
  1022.   CLEAR_FLAG(op,FLAG_APPLIED); /* hack for fixing F_APPLIED in items of dead people */
  1023.   CLEAR_FLAG(op, FLAG_INV_LOCKED);
  1024.   /* If anything below then */
  1025.   if((top=get_map_ob(op->map,op->x,op->y))!=NULL) {
  1026.     /*
  1027.      * There is at least one object present, so we must figure out the order.
  1028.      * First figure out what is on top;
  1029.      */
  1030.  
  1031.     while (top->above != NULL)
  1032.       top = top->above;
  1033.  
  1034.     tmp = top;
  1035.  
  1036.     /*
  1037.      * Rule 0: SEE_ANYWHERE() objects stay on top of the top.
  1038.      */
  1039.     while(tmp != NULL && QUERY_FLAG(tmp,FLAG_SEE_ANYWHERE) &&
  1040.        !QUERY_FLAG(op,FLAG_SEE_ANYWHERE))
  1041.           top = tmp, tmp = tmp->below;
  1042.  
  1043.     /*
  1044.      * Rule 1: Alive objects stay on top.
  1045.      */
  1046.     while(tmp != NULL && QUERY_FLAG(tmp,FLAG_ALIVE) &&
  1047.     !QUERY_FLAG(op,FLAG_ALIVE) && !QUERY_FLAG(op,FLAG_FLYING) &&
  1048.           !QUERY_FLAG(op,FLAG_SEE_ANYWHERE))
  1049.       top = tmp, tmp = tmp->below;
  1050.  
  1051.     /*
  1052.      * Link the new object in the two-way list:
  1053.      */
  1054.  
  1055.     if (top == tmp) {
  1056.       /*
  1057.        * Simple case, insert new object above tmp.
  1058.        */
  1059.       if (tmp->above != NULL)
  1060.         LOG(llevError, "insert_ob_in_map: top == tmp && tmp->above != NULL.\n");
  1061.       else {
  1062.         tmp->above = op;
  1063.         op->below = tmp;
  1064.         op->above = (object *) NULL;
  1065.       }
  1066.     } else {
  1067.       /*
  1068.        * Not so simple case, insert between top and tmp.
  1069.        */
  1070.       if (tmp == NULL) { /* Insert at bottom of map */
  1071.         top->below = op;
  1072.         op->above = top;
  1073.         op->below = (object *) NULL;
  1074.         set_map_ob(op->map, op->x, op->y, op);
  1075.       } else { /* Insert between top and tmp */
  1076.         top->below = op;
  1077.         op->above = top;
  1078.         tmp->above = op;
  1079.         op->below = tmp;
  1080.       }
  1081.     }
  1082.   }
  1083.   else
  1084.     set_map_ob(op->map,op->x,op->y,op);   /* Tell the map that we're here */
  1085.   update_object(op);
  1086.   check_walk_on(op);
  1087.   if(QUERY_FLAG(op,FLAG_FREED))    /* check_walk_on() killed it */
  1088.     return;
  1089.   if(op->type==PLAYER)
  1090.     op->contr->do_los=1;
  1091.   for(tmp=get_map_ob(op->map,op->x,op->y);tmp!=NULL;tmp=tmp->above)
  1092.     switch(tmp->type) {
  1093.     case PLAYER:
  1094.       (*draw_look_func)(tmp);
  1095.       break;
  1096.     case BUTTON:
  1097.     case PEDESTAL:
  1098.       if (op!=tmp)
  1099.         update_button(tmp);
  1100.       break;
  1101.     }
  1102. }
  1103.  
  1104. /*
  1105.  * insert_ob_in_map(op, map):
  1106.  * This function inserts the object in the two-way linked list
  1107.  * which represents what is on a map.
  1108.  * The second argument specifies the map, and the x and y variables
  1109.  * in the object about to be inserted specifies the position.
  1110.  */
  1111.  
  1112. void insert_ob_in_map(object *op,mapstruct *m) {
  1113.   object *tmp, *top;
  1114.   if(m==NULL) {
  1115.     dump_object(op);
  1116.     LOG(llevError,"Trying to insert in null-map!\n%s\n",errmsg);
  1117.     return;
  1118.   }
  1119.   if(out_of_map(m,op->x,op->y)) {
  1120.     dump_object(op);
  1121.     LOG(llevError,"Trying to insert object outside the map.\n%s\n", errmsg);
  1122.     return;
  1123.   }
  1124.   if(!QUERY_FLAG(op,FLAG_REMOVED)) {
  1125.     dump_object(op);
  1126.     LOG(llevError,"Trying to insert (map) inserted object.\n%s\n", errmsg);
  1127.     return;
  1128.   }
  1129.   if(op->more!=NULL)
  1130.     insert_ob_in_map(op->more,m);
  1131.   CLEAR_FLAG(op,FLAG_REMOVED);
  1132.   if(op->nrof)
  1133.     for(tmp=get_map_ob(m,op->x,op->y);tmp!=NULL;tmp=tmp->above)
  1134.       if (CAN_MERGE(op,tmp))
  1135.       {
  1136.         op->nrof+=tmp->nrof;
  1137.         CLEAR_FLAG(op,FLAG_STARTEQUIP);
  1138.         remove_ob(tmp);
  1139.         free_object(tmp);
  1140.       }
  1141.   op->ox=op->x,op->oy=op->y;
  1142.   op->map=m;
  1143.   CLEAR_FLAG(op,FLAG_APPLIED); /* hack for fixing F_APPLIED in items of dead people */
  1144.   CLEAR_FLAG(op, FLAG_INV_LOCKED);
  1145.   /* If there are other objects, then */
  1146.   if((top=get_map_ob(op->map,op->x,op->y))!=NULL) {
  1147.     /*
  1148.      * There is at least one object present, so we must figure out the order.
  1149.      * First figure out what is on top;
  1150.      */
  1151.  
  1152.     while (top->above != NULL)
  1153.       top = top->above;
  1154.  
  1155.     tmp = top;
  1156.  
  1157.     /* Re-did this with nested if statements.  In this way, each check does
  1158.      * not need to check for the previous state - to me, it makes the code
  1159.      * cleaner, and perhaps faster.
  1160.      */
  1161.     if (!QUERY_FLAG(op, FLAG_SEE_ANYWHERE)) {
  1162.       /* See anywhere objects stay on top. */
  1163.       while(tmp != NULL && QUERY_FLAG(tmp,FLAG_SEE_ANYWHERE))
  1164.           top = tmp, tmp = tmp->below;
  1165.  
  1166.       if (!QUERY_FLAG(op, FLAG_ALIVE) && !QUERY_FLAG(op,FLAG_FLYING)) {
  1167.     /* Alive objects also stay on to. */
  1168.     while(tmp != NULL && QUERY_FLAG(tmp,FLAG_ALIVE))
  1169.       top = tmp, tmp = tmp->below;
  1170.  
  1171.         /* Have object 'fall below' other objects that block view, except in
  1172.          * cases where the object has a high visibility (high meaning >0)
  1173.          */
  1174.         if (blocks_view(op->map, op->x, op->y) && (op->face &&
  1175.                 !op->face->visibility)) {
  1176.       while (tmp != NULL && QUERY_FLAG(tmp, FLAG_BLOCKSVIEW) &&
  1177.         !QUERY_FLAG(op, FLAG_BLOCKSVIEW))
  1178.           top = tmp, tmp = tmp->below;
  1179.     }
  1180.       }
  1181.     }
  1182.  
  1183.     /*
  1184.      * Link the new object in the two-way list:
  1185.      */
  1186.  
  1187.     if (top == tmp) {
  1188.       /*
  1189.        * Simple case, insert new object above tmp.
  1190.        */
  1191.       if (tmp->above != NULL)
  1192.         LOG(llevError, "insert_ob_in_map: top == tmp && tmp->above != NULL.\n");
  1193.       else {
  1194.         tmp->above = op;
  1195.         op->below = tmp;
  1196.         op->above = (object *) NULL;
  1197.       }
  1198.     } else {
  1199.       /*
  1200.        * Not so simple case, insert between top and tmp.
  1201.        */
  1202.       if (tmp == NULL) { /* Insert at bottom of map */
  1203.         top->below = op;
  1204.         op->above = top;
  1205.         op->below = (object *) NULL;
  1206.         set_map_ob(op->map, op->x, op->y, op);
  1207.       } else { /* Insert between top and tmp */
  1208.         top->below = op;
  1209.         op->above = top;
  1210.         tmp->above = op;
  1211.         op->below = tmp;
  1212.       }
  1213.     }
  1214.   }
  1215.   else
  1216.     set_map_ob(op->map,op->x,op->y,op);   /* Tell the map that we're here */
  1217.   update_object(op);
  1218.   check_walk_on(op);
  1219.   if(QUERY_FLAG(op,FLAG_FREED))    /* check_walk_on() killed it */
  1220.     return;
  1221.   if(op->type==PLAYER)
  1222.     op->contr->do_los=1;
  1223.   for(tmp=get_map_ob(op->map,op->x,op->y);tmp!=NULL;tmp=tmp->above)
  1224.     switch(tmp->type) {
  1225.     case PLAYER:
  1226.       (*draw_look_func)(tmp);
  1227.       break;
  1228.     case BUTTON:
  1229.     case PEDESTAL:
  1230.       if (op!=tmp)
  1231.         update_button(tmp);
  1232.       break;
  1233.     }
  1234.   /* build up linked list of light sources in each map. We do
  1235.    * this even for non-dark maps, as down the line we might make
  1236.    * a spell/effect which effects the global light of any map.
  1237.    * -b.t.
  1238.    */
  1239. #ifdef USE_LIGHTING
  1240.         if(op->glow_radius>0&&light_not_listed(op)) {
  1241.         add_light_to_map(op,m);
  1242.         update_all_los(m);
  1243.     } else if(m->darkness&&(op->glow_radius>0||op->lights)) /* a light moved, check los */
  1244.         update_all_los(m);
  1245. #endif 
  1246.  
  1247. }
  1248.  
  1249. /*
  1250.  * get_split_ob(ob,nr) splits up ob into two parts.  The part which
  1251.  * is returned contains nr objects, and the remaining parts contains
  1252.  * the rest (or is removed and freed if that number is 0).
  1253.  * On failure, NULL is returned, and the reason put into the
  1254.  * global static errmsg array.
  1255.  */
  1256.  
  1257. object *get_split_ob(object *orig_ob,int nr) {
  1258.   object *tmp, *otmp;
  1259.   if(orig_ob->nrof<nr) {
  1260.     sprintf(errmsg,"There are only %d %ss.",
  1261.             orig_ob->nrof?orig_ob->nrof:1, orig_ob->name);
  1262.     return NULL;
  1263.   }
  1264.   tmp=get_object();
  1265.   copy_object(orig_ob,tmp);
  1266.   if((orig_ob->nrof-=nr)<1) {
  1267.     remove_ob(orig_ob);
  1268.     free_object(orig_ob);
  1269.   }
  1270.   else if(!QUERY_FLAG(orig_ob,FLAG_REMOVED)){
  1271.     if(orig_ob->env!=NULL)
  1272.       sub_weight (orig_ob->env,orig_ob->weight*nr);
  1273.     if((otmp=is_player_inv (orig_ob->env)) && otmp->contr->eric_server <= 0)
  1274.       (*draw_inventory_func)(otmp);
  1275.     else if (orig_ob->env == NULL) {
  1276.       object *tmp;
  1277.       if (orig_ob->map->in_memory!=MAP_IN_MEMORY) {
  1278.         strcpy(errmsg, "Tried to split object whose map is not in memory.");
  1279.     LOG(llevDebug,
  1280.             "Error, Tried to split object whose map is not in memory.\n");
  1281.         return NULL;
  1282.       }
  1283.       for(tmp=get_map_ob(orig_ob->map,orig_ob->x,orig_ob->y);
  1284.           tmp!=NULL;tmp=tmp->above)
  1285.         if(tmp->type==PLAYER && tmp->contr->eric_server <= 0)
  1286.           (*draw_look_func)(tmp);
  1287.     }
  1288.   }
  1289.   tmp->nrof=nr;
  1290.   return tmp;
  1291. }
  1292.  
  1293. /*
  1294.  * decrease_ob_nr(object, number) decreases a specified number from
  1295.  * the amount of an object.  If the amount reaches 0, the object
  1296.  * is subsequently removed and freed.
  1297.  */
  1298.  
  1299. void decrease_ob_nr(object *op,int i) {
  1300.   object *tmp;
  1301.  
  1302.   if((long)(op->nrof-=i)<1) {
  1303.     op->nrof=0;    /* just to be sure that remove_ob handles weight properly */
  1304.     remove_ob(op);
  1305.     /* We don't have remove object send delete to the new client, because
  1306.      * in many areas, more intelligent strategies are employed.  However, if
  1307.      * we are decreasing the number, we can be sure that the object is gone
  1308.      * for good, so send a delete down the line.
  1309.      */
  1310.     tmp=is_player_inv (op->env);
  1311.     if(tmp!=NULL && tmp->contr->eric_server)
  1312.     (*esrv_del_item_func)(tmp->contr->eric_server, op->count);
  1313.     free_object(op);
  1314.   }
  1315.   else
  1316.     if(op->env!=NULL) {
  1317.       sub_weight(op->env,op->weight*i);
  1318.       tmp=is_player_inv (op->env);
  1319.       if(tmp!=NULL) {
  1320.     if (tmp->contr->eric_server)
  1321.         (*esrv_send_item_func)(tmp, op);
  1322.     else
  1323.         (*draw_inventory_func)(tmp);
  1324.       }
  1325.     } else {
  1326.       for(tmp=op->above;tmp!=NULL;tmp=tmp->above)
  1327.         if(tmp->type==PLAYER) 
  1328.       if (tmp->contr->eric_server)
  1329.         (*esrv_send_item_func)(tmp, op);
  1330.       else
  1331.         (*draw_look_func)(tmp);
  1332.     }
  1333. }
  1334.  
  1335. /*
  1336.  * add_weight(object, weight) adds the specified weight to an object,
  1337.  * and also updates how much the environment(s) is/are carrying.
  1338.  */
  1339.  
  1340. void add_weight (object *op, signed long weight) {
  1341.   while (op!=NULL) {
  1342.     if (op->type == CONTAINER) {
  1343.       weight=(signed long)(weight*(100-op->stats.Str)/100);
  1344.     }
  1345.     op->carrying+=weight;
  1346.     op=op->env;
  1347.   }
  1348. }
  1349.  
  1350. /*
  1351.  * insert_ob_in_ob(op,environment):
  1352.  *   This function inserts the object op in the linked list
  1353.  *   inside the object environment.
  1354.  *
  1355.  * Eneq(@csd.uu.se): Altered insert_ob_in_ob to make things picked up enter 
  1356.  * the inventory at the last position or next to other objects of the same
  1357.  * type.
  1358.  * Frank: Now sorted by type, archetype and magic!
  1359.  *
  1360.  * The function returns now pointer to inserted item, and return value can 
  1361.  * be != op, if items are merged. -Tero
  1362.  */
  1363.  
  1364. object *insert_ob_in_ob(object *op,object *where) {
  1365.   object *tmp, *otmp;
  1366.   if(!QUERY_FLAG(op,FLAG_REMOVED)) {
  1367.     dump_object(op);
  1368.     LOG(llevError,"Trying to insert (ob) inserted object.\n%s\n", errmsg);
  1369.     return op;
  1370.   }
  1371.   if(where==NULL) {
  1372.     dump_object(op);
  1373.     LOG(llevError,"Trying to put object in NULL.\n%s\n", errmsg);
  1374.     return op;
  1375.   }
  1376.   if (where->head) {
  1377.     LOG(llevDebug, 
  1378.     "Warning: Tried to insert object wrong part of multipart object.\n");
  1379.     where = where->head;
  1380.   }
  1381.   if (op->more) {
  1382.     LOG(llevError, "Tried to insert multipart object %s (%d)\n",
  1383.         op->name, op->count);
  1384.     return op;
  1385.   }
  1386.   CLEAR_FLAG(op, FLAG_REMOVED);
  1387.   if(op->nrof) {
  1388.     for(tmp=where->inv;tmp!=NULL;tmp=tmp->below)
  1389.       if ( CAN_MERGE(tmp,op) ) {
  1390.     /* return the original object and remove inserted object
  1391.            (client needs the original object) */
  1392.         tmp->nrof += op->nrof;
  1393.     /* Weight handling gets pretty funky.  Since we are adding to
  1394.      * tmp->nrof, we need to increase the weight.
  1395.      */
  1396.     add_weight (where, op->weight*op->nrof);
  1397.         SET_FLAG(op, FLAG_REMOVED);
  1398.         free_object(op); /* free the inserted object */
  1399.         op = tmp;
  1400.         remove_ob (op); /* and fix old object's links */
  1401.         CLEAR_FLAG(op, FLAG_REMOVED);
  1402.     break;
  1403.       }
  1404.  
  1405.     /* I assume combined objects have no inventory
  1406.      * We add the weight - this object could have just been removed
  1407.      * (if it was possible to merge).  calling remove_ob will subtract
  1408.      * the weight, so we need to add it in again, since we actually do
  1409.      * the linking below
  1410.      */
  1411.     add_weight (where, op->weight*op->nrof);
  1412.   } else
  1413.     add_weight (where, (op->weight+op->carrying));
  1414.  
  1415.   otmp=is_player_inv(where);
  1416.   if (otmp&&otmp->contr!=NULL&&!QUERY_FLAG(otmp,FLAG_NO_FIX_PLAYER))
  1417.       fix_player(otmp);
  1418.  
  1419.   op->map=NULL;
  1420.   op->env=where;
  1421.   op->above=NULL;
  1422.   op->below=NULL;
  1423.   op->x=0,op->y=0;
  1424.   op->ox=0,op->oy=0;
  1425.  
  1426. #ifdef USE_LIGHTING /* reset the light list and los of the players on the map */
  1427.   if(op->glow_radius>0&&where->map)
  1428.   {
  1429.       add_light_to_list(op,where);
  1430.       if(light_not_listed(op)) add_light_to_map(op,where->map);
  1431.       if(where->map->darkness&&where->map->players) update_all_los(where->map);
  1432.   }
  1433. #endif
  1434.  
  1435.   if (where->inv==NULL)
  1436.       where->inv=op;
  1437.   else {
  1438.     tmp = where->inv;
  1439.     if (! tmp->invisible) {
  1440.       /*
  1441.        * Rule 1: Move to the similar type
  1442.        */
  1443.       while (tmp->below != NULL &&
  1444.              tmp->type != op->type)
  1445.         tmp = tmp->below;
  1446.  
  1447.       /*
  1448.        * Rule 2: Within similar type, sort by archetype
  1449.        */
  1450.       while (tmp->below != NULL &&
  1451.              tmp->below->type == op->type &&
  1452.              tmp->arch != op->arch)
  1453.         tmp = tmp->below;
  1454.  
  1455.       /*
  1456.        * Rule 3: Within similar type & archetype, sort by magic
  1457.        * First check a special case, then scroll down until
  1458.        * we are below items with more magic.
  1459.        */
  1460.       if (tmp->type == op->type &&
  1461.           tmp->arch == op->arch &&
  1462.           abs(tmp->magic) < abs(op->magic))
  1463.         tmp = tmp->above; /* Beware: tmp might be NULL now. */
  1464.       else {
  1465.         while (tmp != NULL &&
  1466.                tmp->below != NULL &&
  1467.                tmp->below->type == op->type &&
  1468.                tmp->below->arch == op->arch &&
  1469.                abs(tmp->magic) > abs(op->magic))
  1470.           tmp = tmp->below;
  1471.  
  1472.         /*
  1473.          * Rule 4: Insert what seems like a similar item below.
  1474.          */
  1475.         while (tmp != NULL &&
  1476.                tmp->below != NULL &&
  1477.                tmp->below->type == op->type &&
  1478.                tmp->below->arch == op->arch &&
  1479.                abs(tmp->below->magic) == abs(op->magic))
  1480.           tmp = tmp->below;
  1481.       }
  1482.     }
  1483.  
  1484.     /*
  1485.      * Now link the new object into the two-way list, below tmp.
  1486.      */
  1487.     if (tmp == NULL) {
  1488.       op->below = where->inv;
  1489.       op->below->above = op;
  1490.       where->inv = op;
  1491. #if 0 /* commented out, it's not needed and close_container works better */
  1492.     } else if (tmp->above == NULL) { 
  1493.       where->inv = op;
  1494.       op->above = NULL;
  1495.       op->below = tmp;
  1496.       tmp->above = op;
  1497. #endif
  1498.     } else if (tmp->below != NULL) {
  1499.       tmp->below->above = op;
  1500.       op->below = tmp->below;
  1501.       tmp->below = op;
  1502.       op->above = tmp;
  1503.     } else {
  1504.       tmp->below = op;
  1505.       op->above = tmp;
  1506.     }
  1507.   }
  1508.   tmp=is_player_inv(where);
  1509.   if (tmp && tmp->contr->eric_server <= 0) {
  1510.       (*draw_inventory_func)(tmp);
  1511.   }
  1512.   return op;
  1513. }
  1514.  
  1515. /*
  1516.  * Checks if any objects which has the WALK_ON() (or FLY_ON() if the
  1517.  * object is flying) flag set, will be auto-applied by the insertion
  1518.  * of the object into the map (applying is instantly done).
  1519.  * Any speed-modification due to SLOW_MOVE() of other present objects
  1520.  * will affect the speed_left of the object.
  1521.  */
  1522.  /* 4-21-95 added code to check if appropriate skill was readied - this will
  1523.   * permit faster movement by the player through this terrain. -b.t.
  1524.   */
  1525.  
  1526. void check_walk_on(object *op) {
  1527.   object *tmp;
  1528.   if(QUERY_FLAG(op,FLAG_NO_APPLY))
  1529.     return;
  1530.   for(tmp=op->below;tmp!=NULL;tmp=tmp->below) {
  1531.     if (tmp==tmp->below)    /* why? mta */
  1532.        break;
  1533.     if(QUERY_FLAG(tmp,FLAG_SLOW_MOVE)&&!QUERY_FLAG(op,FLAG_FLYING)) { 
  1534.     if(op->type==PLAYER && op->chosen_skill) { 
  1535.              if((QUERY_FLAG(tmp,FLAG_IS_HILLY) && op->contr->shoottype == range_skill 
  1536.         && op->chosen_skill->stats.sp==SK_CLIMBING) 
  1537.             || (QUERY_FLAG(tmp,FLAG_IS_WOODED) && op->contr->shoottype == range_skill
  1538.         && op->chosen_skill->stats.sp==SK_WOODSMAN))
  1539.                   op->speed_left -= (SLOW_PENALTY(tmp)*FABS(op->speed))/4;
  1540.              else 
  1541.         op->speed_left -= SLOW_PENALTY(tmp)*FABS(op->speed);
  1542.     } else 
  1543.         op->speed_left -= SLOW_PENALTY(tmp)*FABS(op->speed);
  1544.     }
  1545.     if(QUERY_FLAG(op,FLAG_FLYING)?QUERY_FLAG(tmp,FLAG_FLY_ON):
  1546.       QUERY_FLAG(tmp,FLAG_WALK_ON)) {
  1547. #if 0
  1548. /* the function that called this (a bit up the line) will draw the
  1549.  * window.  So don't do it here.
  1550.  */
  1551.       if(op->type==PLAYER)
  1552.         (*draw_func)(op);
  1553. #endif
  1554.       if((*apply_func)(op,tmp)==2)
  1555.         break;
  1556.       }
  1557.   }
  1558. }
  1559.  
  1560. /*
  1561.  * present_arch(arch, map, x, y) searches for any objects with
  1562.  * a matching archetype at the given map and coordinates.
  1563.  * The first matching object is returned, or NULL if none.
  1564.  */
  1565.  
  1566. object *present_arch(archetype *at, mapstruct *m, int x, int y) {
  1567.   object *tmp;
  1568.   if(out_of_map(m,x,y)) {
  1569.     LOG(llevError,"Present_arch called outside map.\n");
  1570.     return NULL;
  1571.   }
  1572.   for(tmp=get_map_ob(m,x,y); tmp != NULL; tmp = tmp->above)
  1573.     if(tmp->arch == at)
  1574.       return tmp;
  1575.   return NULL;
  1576. }
  1577.  
  1578. /*
  1579.  * present(type, map, x, y) searches for any objects with
  1580.  * a matching type variable at the given map and coordinates.
  1581.  * The first matching object is returned, or NULL if none.
  1582.  */
  1583.  
  1584. object *present(unsigned char type,mapstruct *m, int x,int y) {
  1585.   object *tmp;
  1586.   if(out_of_map(m,x,y)) {
  1587.     LOG(llevError,"Present called outside map.\n");
  1588.     return NULL;
  1589.   }
  1590.   for(tmp=get_map_ob(m,x,y);tmp!=NULL;tmp=tmp->above)
  1591.     if(tmp->type==type)
  1592.       return tmp;
  1593.   return NULL;
  1594. }
  1595.  
  1596. /*
  1597.  * present_in_ob(type, object) searches for any objects with
  1598.  * a matching type variable in the inventory of the given object.
  1599.  * The first matching object is returned, or NULL if none.
  1600.  */
  1601.  
  1602. object *present_in_ob(unsigned char type,object *op) {
  1603.   object *tmp;
  1604.   for(tmp=op->inv;tmp!=NULL;tmp=tmp->below)
  1605.     if(tmp->type==type)
  1606.       return tmp;
  1607.   return NULL;
  1608. }
  1609.  
  1610. /*
  1611.  * present_arch_in_ob(archetype, object) searches for any objects with
  1612.  * a matching archetype in the inventory of the given object.
  1613.  * The first matching object is returned, or NULL if none.
  1614.  */
  1615.  
  1616. object *present_arch_in_ob(archetype *at, object *op)  {
  1617.   object *tmp;
  1618.   for(tmp=op->inv;tmp!=NULL;tmp=tmp->below)
  1619.     if( tmp->arch == at)
  1620.       return tmp;
  1621.   return NULL;
  1622. }
  1623.  
  1624. /*
  1625.  * set_cheat(object) sets the cheat flag (WAS_WIZ) in the object and in
  1626.  * all it's inventory (recursively).
  1627.  * If checksums are used, a player will get set_cheat called for
  1628.  * him/her-self and all object carried by a call to this function.
  1629.  */
  1630.  
  1631. void set_cheat(object *op) {
  1632.   object *tmp;
  1633.   SET_FLAG(op, FLAG_WAS_WIZ);
  1634.   if(op->inv)
  1635.     for(tmp = op->inv; tmp != NULL; tmp = tmp->below)
  1636.       set_cheat(tmp);
  1637. }
  1638.  
  1639. /*
  1640.  * find_free_spot(archetype, map, x, y, start, stop) will search for
  1641.  * a spot at the given map and coordinates which will be able to contain
  1642.  * the given archetype.  start and stop specifies how many squares
  1643.  * to search (see the freearr_x/y[] definition).
  1644.  * It returns a random choice among the alternatives found.
  1645.  */
  1646.  
  1647. int find_free_spot(archetype *at, mapstruct *m,int x,int y,int start,int stop) {
  1648.   int i,index=0;
  1649.   static int altern[SIZEOFFREE];
  1650.   for(i=start;i<stop;i++) {
  1651.     if(!arch_blocked(at,m,x+freearr_x[i],y+freearr_y[i]))
  1652.       altern[index++]=i;
  1653.     else if(wall(m,x+freearr_x[i],y+freearr_y[i])&&maxfree[i]<stop)
  1654.       stop=maxfree[i];
  1655.   }
  1656.   if(!index) return 0;
  1657.   return altern[RANDOM()%index];
  1658. }
  1659.  
  1660. /*
  1661.  * find_first_free_spot(archetype, mapstruct, x, y) works like
  1662.  * find_free_spot(), but it will search max number of squares.
  1663.  * But it will return the first available spot, not a random choice.
  1664.  */
  1665.  
  1666. int find_first_free_spot(archetype *at, mapstruct *m,int x,int y) {
  1667.   int i;
  1668.   for(i=0;i<SIZEOFFREE;i++)
  1669.     if(!arch_blocked(at,m,x+freearr_x[i],y+freearr_y[i]))
  1670.       return i;
  1671.   return 0;
  1672. }
  1673.  
  1674. /*
  1675.  * find_dir(map, x, y, exclude) will search some close squares in the
  1676.  * given map at the given coordinates for live objects.
  1677.  * It will not considered the object given as exlude among possible
  1678.  * live objects.
  1679.  * It returns the direction toward the first/closest live object if finds
  1680.  * any, otherwise 0.
  1681.  */
  1682.  
  1683. int find_dir(mapstruct *m, int x, int y, object *exclude) {
  1684.   int i,max=SIZEOFFREE;
  1685.   object *tmp;
  1686.   if (exclude && exclude->head)
  1687.     exclude = exclude->head;
  1688.  
  1689.   for(i=1;i<max;i++) {
  1690.     if(wall(m, x+freearr_x[i],y+freearr_y[i]))
  1691.       max=maxfree[i];
  1692.     else {
  1693.       tmp=get_map_ob(m,x+freearr_x[i],y+freearr_y[i]);
  1694.       while(tmp!=NULL && ((tmp!=NULL&&!QUERY_FLAG(tmp,FLAG_MONSTER)&&
  1695.     tmp->type!=PLAYER) || (tmp == exclude || 
  1696.     (tmp->head && tmp->head == exclude))))
  1697.             tmp=tmp->above;
  1698.       if(tmp!=NULL)
  1699.         return freedir[i];
  1700.     }
  1701.   }
  1702.   return 0;
  1703. }
  1704.  
  1705. /*
  1706.  * distance(object 1, object 2) will return the square of the
  1707.  * distance between the two given objects.
  1708.  */
  1709.  
  1710. int distance(object *ob1,object *ob2) {
  1711.   int i;
  1712.   i= (ob1->x - ob2->x)*(ob1->x - ob2->x)+
  1713.          (ob1->y - ob2->y)*(ob1->y - ob2->y);
  1714.   return i;
  1715. }
  1716.  
  1717. /*
  1718.  * find_dir_2(delta-x,delta-y) will return a direction in which
  1719.  * an object which has subtracted the x and y coordinates of another
  1720.  * object, needs to travel toward it.
  1721.  */
  1722.  
  1723. int find_dir_2(int x, int y) {
  1724.   int q;
  1725.   if(!y)
  1726.     q= -300*x;
  1727.   else
  1728.     q=x*100/y;
  1729.   if(y>0) {
  1730.     if(q < -242)
  1731.       return 3 ;
  1732.     if (q < -41)
  1733.       return 2 ;
  1734.     if (q < 41)
  1735.       return 1 ;
  1736.     if (q < 242)
  1737.       return 8 ;
  1738.     return 7 ;
  1739.   }
  1740.   if (q < -242)
  1741.     return 7 ;
  1742.   if (q < -41)
  1743.     return 6 ;
  1744.   if (q < 41)
  1745.     return 5 ;
  1746.   if (q < 242)
  1747.     return 4 ;
  1748.   return 3 ;
  1749. }
  1750.  
  1751. /*
  1752.  * absdir(int): Returns a number between 1 and 8, which represent
  1753.  * the "absolute" direction of a number (it actually takes care of
  1754.  * "overflow" in previous calculations of a direction).
  1755.  */
  1756.  
  1757. int absdir(int d) {
  1758.   while(d<1) d+=8;
  1759.   while(d>8) d-=8;
  1760.   return d;
  1761. }
  1762.  
  1763. /*
  1764.  * dirdiff(dir1, dir2) returns how many 45-degrees differences there is
  1765.  * between two directions (which are expected to be absolute (see absdir())
  1766.  */
  1767.  
  1768. int dirdiff(int dir1, int dir2) {
  1769.   int d;
  1770.   d = abs(dir1 - dir2);
  1771.   if(d>4)
  1772.     d = 8 - d;
  1773.   return d;
  1774. }
  1775.  
  1776. /*
  1777.  * can_pick(picker, item): finds out if an object is possible to be
  1778.  * picked up by the picker.  Returnes 1 if it can be
  1779.  * picked up, otherwise 0.
  1780.  *
  1781.  * Cf 0.91.3 - don't let WIZ's pick up anything - will likely cause
  1782.  * core dumps if they do.
  1783.  */
  1784.  
  1785. int can_pick(object *who,object *item) {
  1786.   return /*QUERY_FLAG(who,FLAG_WIZ)||*/
  1787.          (item->weight>0&&!QUERY_FLAG(item,FLAG_NO_PICK)&&
  1788.      !QUERY_FLAG(item,FLAG_ALIVE)&&
  1789.           (who->type==PLAYER||item->weight<who->weight/3));
  1790. }
  1791.  
  1792.  
  1793. /*
  1794.  * create clone from object to another
  1795.  */
  1796. object *ObjectCreateClone (object *asrc) {
  1797.     object *dst = NULL,*tmp,*src,*part,*prev, *item;
  1798.  
  1799.     if(!asrc) return NULL;
  1800.     src = asrc;
  1801.     if(src->head)
  1802.         src = src->head;
  1803.  
  1804.     prev = NULL;
  1805.     for(part = src; part; part = part->more) {
  1806.         tmp = get_object();
  1807.         copy_object(part,tmp);
  1808.         tmp->x -= src->x;
  1809.         tmp->y -= src->y;
  1810.         if(!part->head) {
  1811.             dst = tmp;
  1812.             tmp->head = NULL;
  1813.         } else {
  1814.             tmp->head = dst;
  1815.         }
  1816.         tmp->more = NULL;
  1817.         if(prev) 
  1818.             prev->more = tmp;
  1819.         prev = tmp;
  1820.     }
  1821.     /*** copy inventory ***/
  1822.     for(item = src->inv; item; item = item->below) {
  1823.     (void) insert_ob_in_ob(ObjectCreateClone(item),dst);
  1824.     }
  1825.  
  1826.     return dst;
  1827. }
  1828.  
  1829. /*** end of object.c ***/
  1830.